﻿using System;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Threading;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using FF14TreasureDiggingTool.DataAccess.ApplicationDbContext;
using FF14TreasureDiggingTool.IOC;
using FF14TreasureDiggingTool.Services;
using FF14TreasureDiggingTool.ViewModels;
using FF14TreasureDiggingTool.Views.Windows;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Wpf.Ui.Demo.Services;
using Wpf.Ui.Demo.Services.Contracts;
using Wpf.Ui.Mvvm.Contracts;
using Wpf.Ui.Mvvm.Services;

namespace FF14TreasureDiggingTool;

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
    public App()
    {
        Syncfusion
            .Licensing
            .SyncfusionLicenseProvider
            .RegisterLicense(
                "Ngo9BigBOggjHTQxAR8/V1NHaF5cXmVCf1FpRmJGdld5fUVHYVZUTXxaS00DNHVRdkdgWXZcdnRRRGFYUkFzXUA="
            );
        IocManager.InitContainer(_host.Services.GetAutofacRoot());
    }

    // The.NET Generic Host provides dependency injection, configuration, logging, and other services.
    // https://docs.microsoft.com/dotnet/core/extensions/generic-host
    // https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
    // https://docs.microsoft.com/dotnet/core/extensions/configuration
    // https://docs.microsoft.com/dotnet/core/extensions/logging
    private static readonly IHost _host = Host.CreateDefaultBuilder()
        .ConfigureAppConfiguration(c =>
        {
            c.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location));
        })
        .ConfigureServices(
            (context, services) =>
            {
                // App Host
                services.AddHostedService<ApplicationHostService>();

                // Page resolver service
                services.AddScoped<IPageService, PageService>();

                // Theme manipulation
                services.AddScoped<IThemeService, ThemeService>();

                // TaskBar manipulation
                services.AddScoped<ITaskBarService, TaskBarService>();
                // Service containing navigation, same as INavigationWindow... but without window
                services.AddScoped<INavigationService, NavigationService>();
                services.AddScoped<IShowWindowService, ShowWindowService>();

                services.AddScoped<IDialogService, DialogService>();
                services.AddScoped<ISnackbarService, SnackbarService>();

                // Main window with navigation
                services.AddScoped<INavigationWindow, Views.Windows.MainWindow>();
                services.AddScoped<ViewModels.MainWindowViewModel>();

                // Views and ViewModels
                services.AddScoped<Views.Pages.DashboardPage>();
                services.AddScoped<ViewModels.DashboardViewModel>();
                services.AddScoped<Views.Pages.SettingsPage>();
                services.AddScoped<ViewModels.SettingsViewModel>();
                services.AddScoped<Views.Pages.ForecastPage>();
                services.AddScoped<ViewModels.ForecastViewModel>();

                services.AddTransient<Views.Pages.FloorInfoPage>();
                services.AddTransient<ViewModels.FloorInfoViewModel>();

                services.AddTransient<Views.Pages.EventPage>();
                services.AddTransient<ViewModels.EventViewModel>();

                services.AddTransient<CustomRuleWindow>();
                services.AddTransient<CustomRuleWindowViewModel>();

                services.AddTransient<TaskManagerWindow>();
                services.AddTransient<TaskManagerViewModel>();

                services.AddTransient<TutorialWindow>();

                services.AddDbContext<ApplicationContext>(ServiceLifetime.Transient);
                var configuration = new ConfigurationBuilder()
                .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .Build();

                services.AddSingleton<IConfiguration>(configuration);
            }
        )
        .UseServiceProviderFactory(new AutofacServiceProviderFactory())
        .ConfigureContainer<ContainerBuilder>(
            iocBuilder => iocBuilder.RegisterModule<AutofacModule>()
        )
        .Build();

    /// <summary>
    /// Gets registered service.
    /// </summary>
    /// <typeparam name="T">Type of the service to get.</typeparam>
    /// <returns>Instance of the service or <see langword="null"/>.</returns>
    public static T GetService<T>()
        where T : class
    {
        return _host.Services.GetService(typeof(T)) as T;
    }

    /// <summary>
    /// Occurs when the application is loading.
    /// </summary>
    private async void OnStartup(object sender, StartupEventArgs e)
    {
        await _host.StartAsync();
    }

    /// <summary>
    /// Occurs when the application is closing.
    /// </summary>
    private async void OnExit(object sender, ExitEventArgs e)
    {
        await _host.StopAsync();

        _host.Dispose();
    }

    /// <summary>
    /// Occurs when an exception is thrown by an application but not handled.
    /// </summary>
    private void OnDispatcherUnhandledException(
        object sender,
        DispatcherUnhandledExceptionEventArgs e
    )
    {
        // For more info see https://docs.microsoft.com/en-us/dotnet/api/system.windows.application.dispatcherunhandledexception?view=windowsdesktop-6.0
    }
}
